package com.loong.android.views.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.view.ViewParent;

import androidx.annotation.Nullable;

import com.loong.android.views.LonView;
import com.loong.android.views.data.BgLinearGradient;
import com.loong.android.views.data.BgRadialGradient;

public class ViewDrawable extends Drawable {
    private android.view.View mView;
    private int mViewWidth = 0;
    private int mViewHeight = 0;
    private float[] mRadii;
    private RectF mRectF;
    private Rect mRect;
    private RectF mRectRoundF;
    private int mBackgroundColor = Color.TRANSPARENT;
    private boolean mIsSetBackgroundColor = false;
    private Bitmap mBackground;
    private Bitmap mRoundBackground;
    private float mBorderWidth = 0;
    private int mBorderColor = Color.TRANSPARENT;
    //是否虚线绘制边框，默认为solid，实线绘制
    private int mBorderType = LonView.BORDER_TYPE_SOLID;
    private float mDashedSpaceWidth = 9;
    private float mDashedLineWidth = 18;

    private float mShadowRadius = 0;
    private float mShadowDx = 0;
    private float mShadowDy = 0;
    private int mShadowColor = Color.TRANSPARENT;

    private Rect mBackgroundRect;
    private Paint mPaint;
    private Paint mShadowClipPaint;
    private Paint mShadowPaint;
    private Paint mRoundPaint;
    private Path mPath;
    private Path mBorderPath;
    private Path mShadowPath;
    private Path mRoundPath;

    private LinearGradient mLinearGradient = null;
    private RadialGradient mRadialGradient = null;
    private BgLinearGradient mBgLinearGradient = null;
    private BgRadialGradient mBgRadialGradient = null;

    private final static Shader.TileMode[] PAINT_TILE_MODE_MAP = {
            Shader.TileMode.CLAMP, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR
    };

    public ViewDrawable(Context context) {
        initDrawable(context);
    }

    public ViewDrawable(android.view.View view) {
        mView = view;
        initDrawable(view.getContext());
    }

    private void initDrawable(Context context) {
        mDashedLineWidth = ViewUtils.dp2px(context, 6);
        mDashedSpaceWidth = ViewUtils.dp2px(context, 3);

        mRadii = new float[]{0, 0, 0, 0, 0, 0, 0, 0};

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

        mRoundPaint = new Paint();
        mRoundPaint.setAntiAlias(true);

        mShadowClipPaint = new Paint();
        mShadowClipPaint.setAntiAlias(true);

        mShadowPaint = new Paint();
        mShadowPaint.setStyle(Paint.Style.FILL);
        mShadowPaint.setAntiAlias(true);


        mPath = new Path();
        mBorderPath = new Path();
        mShadowPath = new Path();
        mRoundPath = new Path();
    }

    private static Shader.TileMode indexToTileMode(int index) {
        if(index < 0 || index >= PAINT_TILE_MODE_MAP.length) return null;
        return PAINT_TILE_MODE_MAP[index];
    }

    private void setSoftwareLayerType() {
        //关闭硬件加速
        mView.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    public void draw(Canvas canvas) {

        mPaint.setStrokeWidth(0);
        if (mPaint.getPathEffect() != null) mPaint.setPathEffect(null);

        canvas.save();

        mPath.reset();
        mPath.addRoundRect(mRectF, mRadii, Path.Direction.CW);

        //绘制阴影
        drawShadow(canvas, mRectF.right - mRectF.left, mRectF.bottom - mRectF.top);

        float vw = Math.abs(mRectF.right - mRectF.left);
        float vh = Math.abs(mRectF.bottom - mRectF.top);

        //绘制背景颜色
        if(mIsSetBackgroundColor) {
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setColor(mBackgroundColor);
            canvas.drawPath(mPath, mPaint);
        }

        if(mBgLinearGradient != null) {
            if(mLinearGradient == null) {
                float x0 = mBgLinearGradient.x0 > 0 && mBgLinearGradient.x0 <= 1 ? mBgLinearGradient.x0 * vw : mBgLinearGradient.x0;
                float y0 = mBgLinearGradient.y0 > 0 && mBgLinearGradient.y0 <= 1 ? mBgLinearGradient.y0 * vh : mBgLinearGradient.y0;
                float x1 = mBgLinearGradient.x1 > 0 && mBgLinearGradient.x1 <= 1 ? mBgLinearGradient.x1 * vw : mBgLinearGradient.x1;
                float y1 = mBgLinearGradient.y1 > 0 && mBgLinearGradient.y1 <= 1 ? mBgLinearGradient.y1 * vh : mBgLinearGradient.y1;
                if(mBgLinearGradient.colors != null) {
                    mLinearGradient = new LinearGradient(x0, y0, x1, y1,
                            mBgLinearGradient.colors, mBgLinearGradient.positions, indexToTileMode(mBgLinearGradient.mode));
                }else {
                    mLinearGradient = new LinearGradient(x0, y0, x1, y1,
                            mBgLinearGradient.color1, mBgLinearGradient.color2, indexToTileMode(mBgLinearGradient.mode));
                }
            }
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
            paint.setStyle(Paint.Style.FILL);
            paint.setShader(mLinearGradient);
            canvas.drawPath(mPath, paint);
        } else if(mBgRadialGradient != null) {
            if(mRadialGradient == null) {
                float centerX = mBgRadialGradient.centerX > 0 && mBgRadialGradient.centerX <= 1 ?
                        mBgRadialGradient.centerX * vw : mBgRadialGradient.centerX;
                float centerY = mBgRadialGradient.centerY > 0 && mBgRadialGradient.centerY <= 1 ?
                        mBgRadialGradient.centerY * vh : mBgRadialGradient.centerY;
                float radius = 0;
                //按最短边的比例计算
                if(mBgRadialGradient.radius >= -1 && mBgRadialGradient.radius < 0) {
                    radius = Math.min(vw, vh) * (-mBgRadialGradient.radius);
                }
                //按最长边的比例计算
                else if(mBgRadialGradient.radius >= -2 && mBgRadialGradient.radius < -1) {
                    radius = Math.max(vw, vh) * (-mBgRadialGradient.radius - 1);
                }
                //按视图宽度的比例计算
                else if(mBgRadialGradient.radius >= -3 && mBgRadialGradient.radius < -2) {
                    radius = vw * (-mBgRadialGradient.radius - 2);
                }
                //按视图高度的比例计算
                else if(mBgRadialGradient.radius >= -4 && mBgRadialGradient.radius < -3) {
                    radius = vh * (-mBgRadialGradient.radius - 3);
                }
                else {
                    radius = mBgRadialGradient.radius;
                }
                radius = radius <= 0 ? Math.min(vw, vh) : radius;
                if(mBgRadialGradient.colors != null) {
                    mRadialGradient = new RadialGradient(centerX, centerY, radius,
                            mBgRadialGradient.colors, mBgRadialGradient.stops, indexToTileMode(mBgRadialGradient.mode));
                }else {
                    mRadialGradient = new RadialGradient(centerX, centerY, radius,
                            mBgRadialGradient.centerColor, mBgRadialGradient.edgeColor, indexToTileMode(mBgRadialGradient.mode));
                }
            }
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
            paint.setStyle(Paint.Style.FILL);
            paint.setShader(mRadialGradient);
            canvas.drawPath(mPath, paint);
        }


        //绘制背景图片
        if (mBackground != null) {
            handleBackgroundRoundBitmap();
            if (mRoundBackground != null) {
                canvas.drawBitmap(mRoundBackground, mRect, mRectF, null);
            }
        }

        //绘制边框
        if (mBorderWidth > 0) {
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setColor(mBorderColor);
            mPaint.setStrokeWidth(mBorderWidth);
            if (mBorderType == LonView.BORDER_TYPE_DASHED) {
                mPaint.setPathEffect(new DashPathEffect(new float[]{mDashedLineWidth, mDashedSpaceWidth}, 0));
            }
            mBorderPath.reset();
            float bw = mBorderWidth / 2;
            float[] ratioRadii = new float[8];
            for (int i = 0; i < mRadii.length; i++) {
                ratioRadii[i] = mRadii[i] - bw;
            }
            mBorderPath.addRoundRect(mRectRoundF, ratioRadii, Path.Direction.CW);
            canvas.drawPath(mBorderPath, mPaint);
        }

        canvas.restore();
    }

    private void handleBackgroundRoundBitmap() {
        if (mRoundBackground != null) return;
        if (mViewWidth <= 0 || mViewHeight <= 0) return;
        mRoundBackground = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.ARGB_8888);
        mRoundPaint.setXfermode(null);
        Canvas canvas = new Canvas(mRoundBackground);
        mRoundPath.reset();
        mRoundPath.addRoundRect(mRectF, mRadii, Path.Direction.CW);
        canvas.drawPath(mRoundPath, mRoundPaint);
        mRoundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(mBackground, mBackgroundRect, mRectF, mRoundPaint);
    }

    private void drawShadow(Canvas canvas, float width, float height) {
        if (mShadowRadius <= 0) return;
        ViewParent parent = mView.getParent();
        if (parent instanceof android.view.ViewGroup) {
            android.view.ViewGroup parentView = (android.view.ViewGroup) parent;
            parentView.setClipChildren(false);
        }
        Bitmap srcBmp = createShadowBitmap((int) (width + mShadowRadius * 2), (int) (height + mShadowRadius * 2));
        canvas.drawBitmap(srcBmp, mShadowDx - mShadowRadius, mShadowDy - mShadowRadius, mShadowClipPaint);//绘制源目标
        srcBmp.recycle();
        srcBmp = null;
    }

    //添加阴影bitmap
    private Bitmap createShadowBitmap(int shadowWidth, int shadowHeight) {

        Bitmap output = Bitmap.createBitmap(shadowWidth, shadowHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        RectF rectF = new RectF(mShadowRadius - mShadowDx, mShadowRadius - mShadowDy,
                shadowWidth - mShadowRadius - mShadowDx, shadowHeight - mShadowRadius - mShadowDy);

        mShadowPaint.setColor(mShadowColor);
        mShadowPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);

        mShadowPath.reset();
        mShadowPath.addRoundRect(rectF, mRadii, Path.Direction.CW);

        //保留shadowPath路径以外区域
        canvas.clipPath(mShadowPath, Region.Op.DIFFERENCE);
        canvas.drawPath(mShadowPath, mShadowPaint);
        return output;
    }

    public ViewDrawable setRadius(float radius) {
        this.mRadii = new float[]{radius, radius, radius, radius, radius, radius, radius, radius};
        return this;
    }

    /**
     * 分别设置四个角的圆角半径
     */
    public ViewDrawable setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) {
        mRadii = new float[]{topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft};
        return this;
    }

    public ViewDrawable setBackgroundColor(int color) {
        mIsSetBackgroundColor = true;
        mBackgroundColor = color;
        return this;
    }

    public ViewDrawable setLinearGradient(BgLinearGradient gradient) {
        mBgLinearGradient = gradient;
        mLinearGradient = null;
        return this;
    }

    public ViewDrawable setRadialGradient(BgRadialGradient gradient) {
        mBgRadialGradient = gradient;
        mRadialGradient = null;
        return this;
    }

    public ViewDrawable setBackground(Bitmap bitmap) {
        mBackground = bitmap;
        mBackgroundRect = null;
        if (mBackground != null) {
            mBackgroundRect = new Rect(0, 0, mBackground.getWidth(), mBackground.getHeight());
        }
        if (mRoundBackground != null) {
            if (!mRoundBackground.isRecycled()) mRoundBackground.recycle();
            mRoundBackground = null;
        }
        return this;
    }

    public ViewDrawable setBorderWidth(float width) {
        mBorderWidth = width;
        return this;
    }

    public ViewDrawable setBorderColor(int color) {
        mBorderColor = color;
        return this;
    }

    public ViewDrawable setBorderType(int borderType) {
        mBorderType = borderType;
        return this;
    }

    public ViewDrawable setBorderDashedParam(float lineWidth, float spaceWidth) {
        mDashedLineWidth = lineWidth;
        mDashedSpaceWidth = spaceWidth;
        return this;
    }

    public ViewDrawable setShadow(float radius, float dx, float dy, int color) {
        mShadowRadius = radius;
        mShadowDx = dx;
        mShadowDy = dy;
        mShadowColor = color;
        return this;
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        mRectF = new RectF(left, top, right, bottom);
        mRect = new Rect(left, top, right, bottom);
        mViewWidth = right - left;
        mViewHeight = bottom - top;
        float bw = mBorderWidth / 2;
        float roundLeft = mRectF.left + bw;
        float roundTop = mRectF.top + bw;
        float roundRight = mRectF.right - bw;
        float roundBottom = mRectF.bottom - bw;
        if (roundRight - roundLeft < 0) roundRight = roundLeft;
        if (roundBottom - roundTop < 0) roundBottom = roundTop;
        mRectRoundF = new RectF(roundLeft, roundTop, roundRight, roundBottom);
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.UNKNOWN;
    }
}
